#pragma once
#include "elisa/elisa.h"
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <gaol/gaol>

#include "Modeler.h"

#ifdef ELISA_PERFORMER
#include "elisa_chrono.h"
#endif

using namespace std;
using namespace elisa;

/* Problem: Caprasse's system

@unpublished{BiniMourrain1996,
author    = {D. Bini and B. Mourrain},
title     = {{Handbook} of {Polynomial} {Systems}},
month     = {November},
year      = {1996}
}
*/
class Caprasse : public Modeler
{
private:
	Model _model;

	RealVar x;
	RealVar y;
	RealVar z;
	RealVar t;
	RealConstraint c1;
	RealConstraint c2;
	RealConstraint c3;
	RealConstraint c4;

public:
	Caprasse()
		: x(Interval(-10,10), "x"),
		  y(Interval(-10,10), "y"),
		  z(Interval(-10,10), "z"),
		  t(Interval(-10,10), "t"),
		  c1(z*(pow(y,2)-1) == 2*x*(1-y*t)),
		  c2(2*z*(y*t-1) == x*(1-pow(t,2))),
		  c3(y*(t*(4*pow(x,2)+2*pow(y,2)-10)-10*y)+
		     x*(z*(4*pow(y,2)+4-pow(x,2))+4*x) == -2),
		  c4(z*(x*(4*pow(t,2)-pow(z,2)+4)+4*z)+
		     t*(y*(4*pow(z,2)+2*pow(t,2)-10)-10*t) == -2),
		  _model()
	{
	}

	elisa::Model & model()
	{
		_model = c1 && c2 && c3 && c4;
		return _model;
	}

	void print()
	{
		cout << '\t' << x.getName() << " = " << x.domain() << endl;
		cout << '\t' << y.getName() << " = " << y.domain() << endl;
		cout << '\t' << z.getName() << " = " << z.domain() << endl;
		cout << '\t' << t.getName() << " = " << t.domain() << endl;
	}

	RealVar & varX()
	{
		return x;
	}
	RealVar & varY()
	{
		return y;
	}
};
